package com.heo.sso.server.controller;

import com.heo.sso.server.dto.TicketGrantingTicket;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.client.RestTemplate;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author 刘康
 * @Date 2020-11-02 11:21
 * @Description
 * @Revision
 **/
@Controller
@Slf4j
public class LoginController {

    private static Map<String, TicketGrantingTicket> redis = new HashMap<>();

    @Value("${sso.server.service.default}")
    private String defaultService;

    /**
     * 1. 如果用户的cookie中没有携带TGC，表示该用户还没有登录过，跳转到登录页面
     * 2. 如果用户的cookie中有TGC,判断TGC是否有效
     * 3. 如果TGC无效,跳转到登录页面
     * 4. 如果TGC有效，获取并通过TGT生成Ticket票据，重定向到service地址
     *
     * @param TGC      票据凭证 cookie中，作为登录后的凭证
     * @param service  要登录到系统
     * @param response 响应
     * @return
     * @throws IOException
     */
    @GetMapping("/")
    public String toLoginPage(@CookieValue(value = "TGC", required = false, defaultValue = "") String TGC,
                              String service, HttpServletResponse response) throws IOException {

        if (service == null || service.equals("")) {
            service = defaultService;
        }

        // 1. 判断cookie中是否有TGC
        log.info("查询TGC");
        if (TGC.equals("")) {
            // 如果没有TGC则跳转登录页面
            log.info("TGC为空，跳转到登录页面");
            log.info("~~~~~~~~~~~~~~");
            return "login";
        }
        log.info("TGC为{}", TGC);

        // 2.判断redis中是否存在TGT （验证TGC是否有效）
        TicketGrantingTicket ticketGrantingTicket = redis.get(TGC);
        if (ticketGrantingTicket == null) {
            log.info("无效的TGC", TGC);
            log.info("~~~~~~~~~~~~~~");
            return "login";
        }

        log.info("TGC有效，生成ticket");
        String ticket = ticketGrantingTicket.grantTicket();
        log.info("ticket:{}", ticket);

        //6. 重定向到service页面
        String serviceURL = service + "?ticket=" + ticket;
        log.info("重定向到serviceURL:{}", serviceURL);
        log.info("~~~~~~~~~~~~~~");
        response.sendRedirect(serviceURL);
        return null;
    }

    @PostMapping("/login")
    @ResponseBody
    public ResponseEntity<?> login(String username, String password, String service, HttpServletResponse response) throws IOException {
        log.info("service:{}", service);
        // 0. 验证service是否在白名称中
        // todo

        // 1. 验证用户名和密码. (调用认证服务)
        log.info("用户登录,验证用户名和密码");
        log.info("username:{}, password:{}", username, password);
        if (!"admin".equals(username) || !"admin".equals(password)) {
            Map<String, String> map = new HashMap<>();
            map.put("msg", "用户名或密码错误");
            log.info("~~~~~~~~~~~~~~");
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("用户名或密码错误");
        }

        // 2 生成票根
        log.info("生成票根");
        TicketGrantingTicket ticketGrantingTicket = new TicketGrantingTicket("admin");
        log.info("TGT: {}", ticketGrantingTicket.getId());
        redis.put(ticketGrantingTicket.getId(), ticketGrantingTicket);

        // 3 把TGC保存在cookie中
        log.info("设置TGC");
        Cookie cookie = new Cookie("TGC", ticketGrantingTicket.getId());
        response.addCookie(cookie);
        log.info("TGC: {}", ticketGrantingTicket.getId());

        // 4.使用TGT生成ST票据
        log.info("生成ticket");
        String ticket = ticketGrantingTicket.grantTicket();
        log.info("ticket: {}", ticket);

        //6. 重定向到service页面
        String serviceURL = service + "?ticket=" + ticket;
        log.info("重定向到serviceURL:{}", serviceURL);
        log.info("~~~~~~~~~~~~~~");
        return ResponseEntity.ok(serviceURL);
    }

    @GetMapping("/logout")
    public String logout(@CookieValue(value = "TGC", required = false, defaultValue = "") String TGC) {
        log.info("单点注销");
        RestTemplate restTemplate = new RestTemplate();
        // 消除TGT
        log.info("正在清除TGT");
        TicketGrantingTicket ticketGrantingTicket = redis.remove(TGC);
        if (ticketGrantingTicket == null) {
            log.info("TGT为空");
            log.info("~~~~~~~~~~~~~~");
            return "login";
        }
        log.info("TGT: {}", ticketGrantingTicket.getId());
        // 根据票根让所有service退出登录
        Map<String, String> serviceMap = ticketGrantingTicket.getServiceMap();
        serviceMap.forEach((ticket, service) -> {
            log.info("注销{}", service);
            log.info("~~~~~~~~~~~~~~");
            restTemplate.postForEntity(service + "logout?ticket=" + ticket, null, String.class);
        });

        return "login";
    }

}
